﻿/* ######################################## *\
 * ### Copyright (C) 2009 AJ Ravindiran ### *
 * ### HTTP://THEAJ.NET/ <AJ@THEAJ.NET> ### *
\* ######################################## */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using AJRavindiran.Jolt.Utilities;
using AJRavindiran.Jolt.RuneScape.Model.Characters;

namespace AJRavindiran.Jolt.RuneScape.Network.Protocols
{
    public class RS2LoginProtocol
    {
        #region Constructors
        /// <summary>
        /// Constructs a new RS2 login protocol for the player's character.
        /// </summary>
        /// <param name="character"></param>
        public RS2LoginProtocol(Character character)
        {
            execute(character);
        }
        #endregion

        #region Metthods
        private void execute(Character character)
        {
            try
            {
                if (character == null || character.GetCodecFactory() == null) return;

                long serverSessionKey = ((long)(new Random(1).NextDouble() * 99999999D) << 32) + (long)(new Random(2).NextDouble() * 99999999D);
                long clientSessionKey = 0;
                int returnCode = RS2UpdateServer.ReturnCodes.LOGIN_OK;

                if (character.LoginStage < -1)
                {
                    RS2UpdateServer.SendUpdateKeys(character);
                }
                else if (character.LoginStage == 0)
                {
                    try
                    {
                        if (!RS2UpdateServer.FillStream(character, 2))
                            return;
                    }
                    catch (Exception ex) { JoltEnvironment.GetLogger().WriteException(ex); return; }

                    int connectionType = character.GetCodecFactory().GetDecoder().ReadUnsignedByte();

                    if (connectionType == 15)
                    {
                        RS2UpdateServer.SendUpdateKeys(character);
                        character.LoginStage = -5;
                        return;
                    }
                    if (connectionType != 14)
                    {
                        character.LoginStage = -1;
                        return;
                    }

                    int longPlayerName = character.GetCodecFactory().GetDecoder().ReadUnsignedByte();
                    character.GetCodecFactory().GetEncoder().WriteByte(0);
                    character.GetCodecFactory().GetEncoder().WriteQWord(serverSessionKey);
                    RS2UpdateServer.DirectFlushStream(character);
                    character.LoginStage++;
                }
                else if (character.LoginStage == 1)
                {
                    try
                    {
                        if (!RS2UpdateServer.FillStream(character, 3))
                            return;
                    }
                    catch (Exception ex) { JoltEnvironment.GetLogger().WriteException(ex); return; }

                    int loginType = character.GetCodecFactory().GetDecoder().ReadUnsignedByte();

                    if (loginType != 16 && loginType != 18 && loginType != 14)
                    {
                        character.LoginStage = -1;
                        return;
                    }
                    character.LoginStage++;
                }
                else if (character.LoginStage == 2)
                {
                    int loginPacketSize = character.GetCodecFactory().GetDecoder().ReadUnsignedByte();
                    int loginEncrypedPacketSize = loginPacketSize - (36 + 1 + 1 + 2);

                    if (loginEncrypedPacketSize <= 0)
                    {
                        character.LoginStage = -1;
                        return;
                    }

                    try
                    {
                        if (!RS2UpdateServer.FillStream(character, loginPacketSize))
                            return;
                    }
                    catch (Exception ex) { JoltEnvironment.GetLogger().WriteException(ex); return; }

                    int clientVersion = character.GetCodecFactory().GetDecoder().ReadDWord();

                    if (clientVersion != 508)
                    {
                        character.LoginStage = 1;
                        return;
                    }

                    character.GetCodecFactory().GetDecoder().ReadUnsignedByte();
                    character.GetCodecFactory().GetDecoder().ReadUnsignedWord();
                    character.GetCodecFactory().GetDecoder().ReadUnsignedWord();

                    for (int i = 0; i < 24; i++)
                    {
                        int CacheIndex = character.GetCodecFactory().GetDecoder().ReadUnsignedByte();
                    }
                    string junk = character.GetCodecFactory().GetDecoder().ReadString();
                    for (int i = 0; i < 29; i++)
                    {
                        int junk2 = character.GetCodecFactory().GetDecoder().ReadDWord();
                    }
                    loginEncrypedPacketSize--;
                    int junk29 = character.GetCodecFactory().GetDecoder().ReadUnsignedByte();
                    int encryption = character.GetCodecFactory().GetDecoder().ReadUnsignedByte();

                    if (encryption != 10 && encryption != 64)
                    {
                        character.LoginStage = -1;
                        return;
                    }

                    clientSessionKey = character.GetCodecFactory().GetDecoder().ReadQWord();
                    serverSessionKey = character.GetCodecFactory().GetDecoder().ReadQWord();
                    character.GetDetails().Username = MathUtilities.LongToString(character.GetCodecFactory()
                        .GetDecoder().ReadQWord()).ToLower().Replace("_", " ").Trim();

                    if (character.GetDetails().Username == null)
                    {
                        character.LoginStage = -1;
                        character.GetDetails().Username = "";
                        return;
                    }

                    for (int i = 0; i < character.GetDetails().Username.Length; i++)
                    {
                        char c = character.GetDetails().Username[i];

                        if (!char.IsLetterOrDigit(c) && !char.IsWhiteSpace(c))
                        {
                            character.LoginStage = -1;
                            character.GetDetails().Username = "";
                            return;
                        }
                    }

                    if (RuneScape.GetEngine().GetCharacterManager().PlayerOnline(character.GetDetails().Username, character))
                    {
                        returnCode = -5; 
                    }

                    string password = character.GetCodecFactory().GetDecoder().ReadString();

                    if (password == null)
                    {
                        character.LoginStage = -1;
                        return;
                    }

                    character.GetCodecFactory().GetEncoder().WriteByte(returnCode);
                    character.GetCodecFactory().GetEncoder().WriteByte(character.GetDetails().Rights);
                    character.GetCodecFactory().GetEncoder().WriteByte(0);
                    character.GetCodecFactory().GetEncoder().WriteByte(0);
                    character.GetCodecFactory().GetEncoder().WriteByte(0);
                    character.GetCodecFactory().GetEncoder().WriteByte(1);
                    character.GetCodecFactory().GetEncoder().WriteByte(0);
                    character.GetCodecFactory().GetEncoder().WriteByte(character.GetDetails().ConnectionID);
                    character.GetCodecFactory().GetEncoder().WriteByte(0);

                    RS2UpdateServer.DirectFlushStream(character);
                }
            }
            catch (Exception ex) { JoltEnvironment.GetLogger().WriteException(ex); }
        }
        #endregion
    }
}
